﻿#-------------------------------------------------------------------------------
# Name:        store.py
# Purpose:
#
# Author:      yoyo
#
# Created:     20-02-2008
# Copyright:   (c) yoyo 2008
# Licence:     <your licence>
#-------------------------------------------------------------------------------
#!/usr/bin/env python
import os, sys

import storepacket
import db
import dbctrl
if False:
    import storm.locals as storm
    import storm.store as storm_store

def log(*msg):
    print msg
    
_debug = True
def errorlog():
    if _debug:
        import traceback
        print traceback.print_exc()
    
class Store(object):
    def __init__(self):
        if False:
            self._dbctrl = dbctrl.DbCtrl()
        """ 初始化 """
        #self.parser = dataParser.DataParser(self)
        self._dbctrl = dbctrl.DbCtrl(self)
        self._request = RequestHandler(self)
        self._response = ResponseHandler(self)


    def peerStateChange(self, peerID, state):
        """ Peer状态变化 """
        log('peerStateChange', peerID, state)
        pass

    def receivedata(self, peerid, data):
        """接受数据,回调函数"""
        log('receivedata', peerid, data)
        sp = storepacket.StorePacket(data)
        self._request.handle(peerid, sp)

    def senddata(self, peerid, subpacket):
        """ 发送数据 """
        if False:
            subpacket = storepacket.BasePacket()
        mainpacket = storepacket.StorePacket()
        mainpacket.data = subpacket
        mainpacket.type = subpacket.packettype()
        mainpacket.ver = storepacket.CURRENT_VERSION

        data = str(mainpacket)
        #调用发送函数
        p2psenddata(peerid, data)
        
def p2psenddata(peerid, data):
    """ 占位的，这个方法会被外部模块替换掉 """
    print u" 占位的，这个方法会被外部模块替换掉 "

class RequestHandler(object):
    def __init__(self, store):
        if False:
            self._store = Store()
            self._dbctrl = dbctrl.DbCtrl()

        self._store = store
        self._dbctrl = store._dbctrl
        self._typesw = {
                storepacket.TYPE_CS_LOGIN: self.CS_LOGIN
            }

    def handle(self, peerid, packet):
        try:
            self._typesw[packet.type](peerid, packet.data)
        except:
            errorlog()


    def CS_LOGIN(self, peerid, packet):
        """ 登陆后，发送客户保存的块列表:cacheSize(int)+Count+(UrlHash+PieceRange)列表 """
        if False:
            ipeer = db.DBPeer()
            packet = storepacket.CS_LOGIN()

        ipeer = self._dbctrl.getdbpeer(peerid)
        if not ipeer:
            ipeer = self._dbctrl.newdbpeer(peerid) #新建
        ipeer.active = True
        ipeer.cachsize = packet.cachesize

        #更新块信息
        urlhash_urlcost_list = []
        urlhash_list = []

        ipeer.deleteallpieces()  #错误 ipeer.pieces.clear()是清除关联
        
        for i in range(packet.count):
            urlhash, piecestart, pieceend = packet.urlhash_piecerange_list[i*3:i*3+3]
            idburl = self._dbctrl.getdburl(urlhash)
            
            #创建新的url纪录
            if not idburl:
                idburl = self._dbctrl.newdburl(urlhash)
                
            if idburl:
                p1 = self._dbctrl.newdbpiece()
                p1.urlhash = urlhash
                p1.piecestart = piecestart
                p1.pieceend = pieceend
                ipeer.pieces.add(p1)

                urlhash_urlcost_list.append(urlhash)
                urlhash_urlcost_list.append(idburl.urlcost)
                if not idburl.url:
                    urlhash_list.append(urlhash)

        #保存数据
        self._dbctrl.flush()

        #应答
        self._store._response.SC_RESPONSE_LOGIN(peerid,
            len(urlhash_urlcost_list)/2, urlhash_urlcost_list)

        #通过UrlHash值，查询真实的url
        if len(urlhash_list) > 0:
            self._store._response.SC_REQUEST_URLLIST(peerid, urlhash_list)


    def CS_REQUEST_URL(self, peerid, packet):
        """ 请求某url可用的下载块列表:UrlHash+PieceRange """
        if False:
            ipeer = db.DBPeer()
            ipiece = db.DBPiece()
            iurl = db.DBUrl()
            ipeers = storm_store.ResultSet()
        iurl = self._dbctrl.getdburl(packet.urlhash)
        ipeers = self._dbctrl.findpeers(packet.urlhash, packet.piecestart, packet.pieceend)

        #调用发送信息段
        icount = ipeers.count()
        ipeerid_list = [ipeers[i].peerid for i in range(min(20, icount))]
        self._store._response.SC_URLPIECES(peerid, iurl.urlhash, iurl.urlcost,\
            icount, ipeerid_list)


    def CS_RESPONSE_URLLIST(self, peerid, packet):
        """ 查询真实url的返回数据:(UrlHash+url+回车符(\n))列表 """
        if False:
            idburl = db.DBUrl()
        ilist = packet.urldm5_url_list
        for urlhash, url in ilist:
            idburl = self._dbctrl.getdburl(urlhash)
            if idburl and not idburl.url:
                idburl.url = url

        #保存数据
        self._dbctrl.flush()

class ResponseHandler(object):
    def __init__(self, store):
        if False:
            self._store = Store()
            self._dbctrl = dbctrl.DbCtrl()
        self._store = store
        self._dbctrl = store._dbctrl

    @staticmethod
    def setpacket(packet, localsdict):
        for k,v in localsdict.iteritems():
            if not k in ['self', 'peerid'] and v<>packet:
                setattr(packet, k, v)

    def senddata(self, peerid, packet):
        self._store.senddata(peerid, packet)


    def SC_RESPONSE_LOGIN(self, peerid, count, urlhash_urlcost_list):
        """ 发送客户端登陆回应信息:Count+(UrlHash+urlCost)列表 """
        packet = storepacket.SC_RESPONSE_LOGIN()
        self.setpacket(packet, locals())

        self.senddata(peerid, packet)


    def SC_URLPIECES(self, peerid, urlhash, urlcost, piecestart, pieceend,
        count, peerid_list):
        """ 发送某url可用的下载块列表:UrlHash+UrlCost+Count+PeerID列表 """
        packet = storepacket.SC_URLPIECES()
        self.setpacket(packet, locals())

        self.senddata(peerid, packet)


    def SC_SAVE_URLPIECES(self, peerid, urlcost, piecestart, pieceend, url):
        """ 主动要求客户下载保存某些块:UrlCost+PieceRange+Url """
        packet = storepacket.SC_SAVE_URLPIECES()
        self.setpacket(packet, locals())

        self.senddata(peerid, packet)


    def SC_REQUEST_URLLIST(self, peerid, count, urlhash_list):
        """ 通过UrlHash值，查询真实的url:Count+UrlHash列表 """
        packet = storepacket.SC_REQUEST_URLLIST()
        self.setpacket(packet, locals())

        self.senddata(peerid, packet)


#全局对象
golbal_store = Store()

def test():
    golbal_store.receivedata('id', storepacket.makepacket(storepacket.TYPE_CS_LOGIN))
    import sha
    golbal_store._response.SC_RESPONSE_LOGIN('peerid', 1, [sha.new('urlhash').digest(), 3])

if __name__ == '__main__':
    test()






